﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
using System.Windows.Threading;
using System.ComponentModel;

namespace Invini.Localization
{
    public class LocalizationManager : ILocalizationManager
    {
        public event LocalizationCultureChangedEventHandler CultureChanged;
        public event LocalizationContextChangedEventHandler ContextChanged;

        private static LocalizationManager _current;
        public static ILocalizationManager Current
        {
            get
            {
                if (_current == null)
                    _current = new LocalizationManager();

                return _current;
            }
        }

        public LocalizationSettings Settings
        {
            get;
            private set;
        }

        public LocalizedContent GetLocalizedContent(LocalizationSet set, object defaultContent, object context = null, DependencyObject target = null)
        {
            if (defaultContent == null)
                throw new ArgumentNullException("defaultContent");

            CultureInfo targetCulture = this.Settings.Culture;
            
            object content = defaultContent;
            object invariantContent = defaultContent;

            if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
            {
                CultureInfo culture = null;
                while (target != null)
                {
                    if ((culture = LocalizationSettings.GetDesignCulture(target)) != null)
                        break;

                    target = LogicalTreeHelper.GetParent(target);
                }

                if (culture != null)
                    targetCulture = culture;
            }

            if (targetCulture != null &&
                set != null &&
                set.Localizations != null &&
                set.Localizations.Count != 0)
            {
                foreach (Localization localization in set.Localizations)
                {
                    if (localization.Culture.Name == CultureInfo.InvariantCulture.Name)
                    {
                        invariantContent = localization.Content;
                        break;
                    }
                }


                object localizedContent = null;
                CultureInfo tmpCulture = targetCulture;
                while (tmpCulture != null)
                {
                    foreach (Localization localization in set.Localizations)
                    {
                        if (localization.Culture.Name == tmpCulture.Name)
                        {
                            localizedContent = localization.Content;
                            break;
                        }
                    }

                    if (localizedContent != null)
                        break;

                    if (tmpCulture == CultureInfo.InvariantCulture)
                        break;

                    tmpCulture = tmpCulture.Parent;
                }

                if (localizedContent != null)
                    content = localizedContent;
            }

            if (content != null && content is FrameworkElement && context != null)
            {
                FrameworkElement contentFramework = content as FrameworkElement;
                contentFramework.Language = XmlLanguage.GetLanguage(this.Settings.Culture.IetfLanguageTag);
                contentFramework.DataContext = context;
                contentFramework.Dispatcher.Invoke(delegate { }, DispatcherPriority.Loaded);
            }

            return new LocalizedContent(content, invariantContent);
        }

        private LocalizationManager()
        {
            LocalizationSettings.CultureChanged += this.settingsCultureChanged;
            Localization.ContextChanged += this.localizationContextChanged;

            this.Settings = new LocalizationSettings();
            //this.Settings.Culture = new CultureInfo("en");
            this.Settings.Culture = CultureInfo.CurrentUICulture;
        }

        private void settingsCultureChanged(object sender, LocalizationCultureChangedEventArgs e)
        {
            this.onCultureChanged(e);
        }
        private void localizationContextChanged(object sender, LocalizationContextChangedEventArgs e)
        {
            this.onContextChanged(e);
        }
        private void onCultureChanged(LocalizationCultureChangedEventArgs e)
        {
            if (this.CultureChanged != null)
                this.CultureChanged(this, e);
        }
        private void onContextChanged(LocalizationContextChangedEventArgs e)
        {
            if (this.ContextChanged != null)
                this.ContextChanged(this, e);
        }
    }
}
